package middleware

import (
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"github.com/gin-gonic/gin"
)

// Logger 是一个自定义的日志中间件
func Logger() gin.HandlerFunc {
	// 日志文件路径
	logFilePath := "./logs/"
	// 日志文件名前缀
	logFileName := "gin-server"
	// 日志文件后缀
	logFileExt := "log"
	// 日志文件最大大小，单位为 MB
	logFileMaxSize := 1000
	// 日志文件切割的时间间隔，单位为天
	logFileSplitDays := 1

	// 检查日志目录是否存在，不存在则创建
	err := os.MkdirAll(logFilePath, os.ModePerm)
	if err != nil {
		log.Fatalf("Failed to create log directory: %v", err)
	}

	// 获取当前时间的年月日
	now := time.Now()
	year, month, day := now.Date()

	// 构造日志文件名
	logFileName = fmt.Sprintf("%s-%d-%02d-%02d", logFileName, year, month, day)

	// 打开日志文件
	logFile, err := os.OpenFile(
		fmt.Sprintf("%s/%s.%s", logFilePath, logFileName, logFileExt),
		os.O_WRONLY|os.O_APPEND|os.O_CREATE,
		0666,
	)
	if err != nil {
		log.Fatalf("Failed to open log file: %v", err)
	}

	// 设置日志输出
	writers := []io.Writer{
		logFile,
		os.Stdout}
	log.SetOutput(io.MultiWriter(writers...))
	log.SetFlags(log.Ldate | log.Ltime | log.LUTC)

	return func(c *gin.Context) {
		// 处理请求前记录日志
		// 开始时间
		startTime := time.Now()
		// 调用该请求的剩余处理程序
		c.Next()
		// 结束时间
		endTime := time.Now()
		// 执行时间
		latencyTime := endTime.Sub(startTime)

		// 请求IP
		clientIP := c.ClientIP()
		// remoteIP := c.RemoteIP()

		// 请求方式
		reqMethod := c.Request.Method
		// 请求路由
		reqUri := c.Request.RequestURI
		// 请求协议
		reqProto := c.Request.Proto
		// 请求来源
		repReferer := c.Request.Referer()
		// 请求UA
		reqUA := c.Request.UserAgent()

		// 请求响应内容长度
		resLength := c.Writer.Size()
		if resLength < 0 {
			resLength = 0
		}
		// 响应状态码
		statusCode := c.Writer.Status()

		log.Printf(
			"%s | %3d | %s %10s | \033[44;37m%-6s\033[0m %s %s  | %10v | \"%s\" \"%s\"",
			colorForStatus(statusCode),
			statusCode,
			colorForStatus(0),
			clientIP,
			// remoteIP,
			reqMethod,
			reqUri,
			reqProto,
			latencyTime,
			reqUA,
			repReferer,
		)

		// 判断日志文件是否需要切割
		fileInfo, err := logFile.Stat()
		if err != nil {
			log.Fatalf("Failed to get log file info: %v", err)
		}
		_, _, lastDay := endTime.AddDate(0, 0, -1*logFileSplitDays).Date()
		if fileInfo.Size() > int64(logFileMaxSize*1024*1024) {
			// 关闭当前日志文件
			logFile.Close()
			// 构造新的日志文件名
			logFileName = fmt.Sprintf("%s-%s", logFileName, time.Now().Format("2006-01-02-15"))

			// 创建新的日志文件
			logFile, err = os.OpenFile(
				fmt.Sprintf("%s/%s.%s", logFilePath, logFileName, logFileExt),
				os.O_WRONLY|os.O_APPEND|os.O_CREATE,
				0666,
			)
			if err != nil {
				log.Fatalf("Failed to create log file: %v", err)
			}
			// 设置日志输出
			log.SetOutput(logFile)
			log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
		} else if fileInfo.ModTime().Day() == lastDay {
			// 关闭当前日志文件
			logFile.Close()

			// 构造新的日志文件名
			logFileName = fmt.Sprintf("%s-%s", logFileName, endTime.Format("2006-01-02"))

			// 创建新的日志文件
			logFile, err = os.OpenFile(
				fmt.Sprintf("%s/%s.%s", logFilePath, logFileName, logFileExt),
				os.O_WRONLY|os.O_APPEND|os.O_CREATE,
				0666,
			)
			if err != nil {
				log.Fatalf("Failed to create log file: %v", err)
			}
			// 设置日志输出
			log.SetOutput(logFile)
			log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
		}
	}
}

// colorForStatus 根据 HTTP 状态码返回 ANSI 颜色代码
func colorForStatus(code int) string {
	switch {
	case code >= 200 && code < 300:
		return "\033[42;1;37m" // green
	case code >= 300 && code < 400:
		return "\033[34m" // blue
	case code >= 400 && code < 500:
		return "\033[33m" // yellow
	case code == 0:
		return "\033[0m" // cancel
	default:
		return "\033[31m" // red
	}
}
